package aso.fighting_groups;

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import sim.engine.SimState;
import sim.engine.Steppable;

/**
 * Provides logging facilities.
 */
class Logger implements Steppable {

    /**
     * UID for serialization.
     */
    private static final long serialVersionUID = 6332780504302115162L;

    /**
     * A BufferedWriter.
     */
    private BufferedWriter writer;

    /**
     * @param fileName
     *            the file name to log to
     * @throws IOException
     *             thrown if there is a problem while performing the I/O
     *             operations
     */
    public Logger(final String fileName) throws IOException {
        Path path = Paths.get(fileName);
        writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8);
    }

    @Override
    public final void step(final SimState state) {

        FightingGroups fg = (FightingGroups) state;

        // if this is the first time -> print sim. parameter
        // if (firstTime) {
        // firstTime = false;
        //
        // try {
        // writer.write(Double.toString(fg.foodSpawnProbability) + " ");
        // writer.write(Double.toString(fg.foodConsumptionRate) + " ");
        // writer.write(Integer.toString(fg.teamCount) + " ");
        // writer.write(Integer.toString(fg.agentCount) + " ");
        // writer.write(Double.toString(fg.starvationImportance) + " ");
        // writer.write(Double.toString(fg.MAX_SMELL) + " ");
        // writer.write(Double.toString(fg.MAX_FOOD));
        // writer.newLine();
        // }
        // catch (IOException e) {
        // e.printStackTrace();
        // }
        // }

        // count the stats

        double foodInEnvironment = 0;
        for (int i = 0; i < fg.getGridWidth(); ++i) {
            for (int j = 0; j < fg.getGridHeight(); ++j) {
                foodInEnvironment += fg.getFoodGrid().field[i][j];
            }
        }

        int[][] intValues = new int[fg.getTeamCount()][6]; // agents count,
                                                           // starving
                                                           // count, longest
                                                           // starvation,
                                                           // groups
                                                           // count, max Group
                                                           // Size, max g
                                                           // starvation
        double[][] doubleValues = new double[fg.getTeamCount()][7]; // average
        // starvation,
        // average food,
        // max food,
        // average
        // groupSize,
        // avg g
        // starvation,
        // avg g food,
        // max g food,

        for (int i = 0; i < fg.getAgents().length; ++i) {
            Agent a = fg.getAgents()[i];
            intValues[a.getTeam()][0]++; // increase count of agents in the team
            if (a.getStarvingIterations() > 0) {
                intValues[a.getTeam()][1]++;
            }
            if (a.getStarvingIterations() > intValues[a.getTeam()][2]) {
                intValues[a.getTeam()][2] = a.getStarvingIterations();
            }
            doubleValues[a.getTeam()][0] += a.getStarvingIterations();
            doubleValues[a.getTeam()][1] += a.getCarryingFoodAmount();
            if (a.getCarryingFoodAmount() > doubleValues[a.getTeam()][2]) {
                doubleValues[a.getTeam()][2] += a.getCarryingFoodAmount();
            }
        }

        for (int i = 0; i < fg.getGroups().size(); ++i) {
            Group g = (Group) fg.getGroups().get(i);
            intValues[g.getTeam()][3]++;
            if (g.getMembers().size() > intValues[g.getTeam()][4]) {
                intValues[g.getTeam()][4] = g.getMembers().size();
            }
            doubleValues[g.getTeam()][3] += g.getMembers().size();
            doubleValues[g.getTeam()][4] += ((Agent) g.getMembers().get(0)).getStarvingIterations();
            if (((Agent) g.getMembers().get(0)).getStarvingIterations() > intValues[g.getTeam()][5]) {
                intValues[g.getTeam()][5] = ((Agent) g.getMembers().get(0)).getStarvingIterations();
            }
            doubleValues[g.getTeam()][5] += ((Agent) g.getMembers().get(0)).getCarryingFoodAmount();
            if (((Agent) g.getMembers().get(0)).getCarryingFoodAmount() > doubleValues[g.getTeam()][6]) {
                doubleValues[g.getTeam()][6] = ((Agent) g.getMembers().get(0)).getCarryingFoodAmount();
            }
        }

        for (int t = 0; t < fg.getTeamCount(); ++t) {
            if (intValues[t][0] != 0) {
                doubleValues[t][0] /= intValues[t][0];
                doubleValues[t][1] /= intValues[t][0];
            } else {
                doubleValues[t][0] = 0;
                doubleValues[t][0] = 0;
            }
            if (intValues[t][3] != 0) {
                doubleValues[t][3] /= intValues[t][3];
                doubleValues[t][4] /= intValues[t][3];
                doubleValues[t][5] /= intValues[t][3];
            } else {
                doubleValues[t][3] = 0;
                doubleValues[t][4] = 0;
                doubleValues[t][5] = 0;
            }

            try {
                for (int i = 0; i < intValues[t].length; ++i) {
                    writer.write(Integer.toString(intValues[t][i]) + " ");
                }
                for (int i = 0; i < doubleValues[t].length; ++i) {
                    writer.write(Double.toString(doubleValues[t][i]) + " ");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try {
            writer.write(Double.toString(foodInEnvironment));
            writer.newLine();
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
